// #define DEBUG

#include <stdio.h>
#include <stdbool.h>
#include <memory.h>
#include <stdint.h>

#include <stddef.h>

#ifndef VHDLSENDER_HEADER_H
#define VHDLSENDER_HEADER_H

enum VC_TYPE {
    VC_4,
    VC_12
};

// VC-4结构定义
typedef struct {
    uint16_t MFI;
    char load[2340];
} vc4FrameBody_t;

typedef struct {
    uint16_t logicalChannelID;
    uint16_t physicalChannelID;
    uint16_t SQ;
    enum VC_TYPE vcType;
    size_t frameLength;
    uint16_t frameNum;
    vc4FrameBody_t frameBody;
} vc4FrameFull_t;

// VC-12结构定义
typedef struct {
    uint16_t MFI;
    char load[136];
} vc12FrameBody_t;

typedef struct {
    uint16_t logicalChannelID;
    uint16_t physicalChannelID;
    uint16_t SQ;
    enum VC_TYPE vcType;
    size_t frameLength;
    uint16_t frameNum;
    vc12FrameBody_t frameBody;
} vc12FrameFull_t;

typedef struct {
    uint16_t logicalChannelID;
    uint16_t physicalChannelID;
    uint16_t SQ;
    enum VC_TYPE vcType;
    size_t frameLength;
    uint16_t frameNum;
    uint16_t MFI;
} vcTypeHeader_t;

enum GENERATE_DATA_TYPE {
    FIXED = 0,

};


const size_t VC4_FRAME_FULL_LENGTH = sizeof(vc4FrameFull_t); // 单个VC-4帧结构,包含开销
const size_t VC4_FRAME_BODY_LENGTH = sizeof(vc4FrameBody_t);
const size_t VC4_FRAME_LOAD_LENGTH = (sizeof(vc4FrameBody_t) - sizeof(uint16_t));

const size_t VC12_FRAME_FULL_LENGTH = sizeof(vc12FrameFull_t);                    // 单个VC-12帧结构,包含开销
const size_t VC12_FRAME_BODY_LENGTH = sizeof(vc12FrameBody_t);
const size_t VC12_FRAME_LOAD_LENGTH = (sizeof(vc12FrameBody_t) - sizeof(uint16_t));

const size_t VC_FRAME_HEADER_LENGTH = sizeof(vcTypeHeader_t);

#endif

///////////////////////////////////////////////////////
// TODO:


void printVCTypeHeader(const vcTypeHeader_t *header) {
    printf("logicalChannelID: %u\n", header->logicalChannelID);
    printf("physicalChannelID: %u\n", header->physicalChannelID);
    printf("SQ: %u\n", header->SQ);

    switch (header->vcType) {
        case VC_4:
            printf("vcType: VC_TYPE4\n");
            break;
        case VC_12:
            printf("vcType: VC_TYPE12\n");
            break;
        default:
            printf("vcType: Unknown\n");
            break;
    }

    printf("frameLength: %zu\n", header->frameLength);
    printf("frameNum: %u\n", header->frameNum);
    printf("MFI: %u\n", header->MFI);
}


/**
 * @brief 通过要填充的数据长度(LOAD数) 得到填充完毕后一行的Frame数量.
 * @param bufferLength
 * @param vcType
 * @param splitedCols
 * @return
 */
size_t getFrameNumOneLineFromBufferLength(size_t bufferLength, enum VC_TYPE vcType, uint16_t splitedCols) {
    if (bufferLength == 0) {
        return 0;
    }

    // bufferLength 来的是需要承载的数据, 不包含开销, 所以这里是BodyLength
    size_t vcTypeLoadLength;
    size_t frameNum;

    switch (vcType) {
        case VC_4:
            vcTypeLoadLength = VC4_FRAME_LOAD_LENGTH;
            break;
        case VC_12:
            vcTypeLoadLength = VC12_FRAME_LOAD_LENGTH;
            break;
        default:
            vcTypeLoadLength = VC4_FRAME_LOAD_LENGTH;
            break;
    }

    frameNum = bufferLength / splitedCols / vcTypeLoadLength;
    // 数据块过小,得到的是0;
    if (frameNum == 0) {
        frameNum++;
    } else if (bufferLength % (splitedCols * vcTypeLoadLength) != 0) {
        // 得到的结果不是整数倍.
        frameNum++;
    }

    return frameNum;
}

size_t getFrameNumOneLineFromOneLineLength(enum VC_TYPE vcType, size_t oneLineLength) {
    if (oneLineLength == 0) {
        return 0;
    }

    // fullLength 来的是需要承载的数据
    size_t vcTypeFullLength;
    size_t frameNum;

    switch (vcType) {
        case VC_4:
            vcTypeFullLength = VC4_FRAME_LOAD_LENGTH;
            break;
        case VC_12:
            vcTypeFullLength = VC12_FRAME_LOAD_LENGTH;
            break;
        default:
            vcTypeFullLength = VC4_FRAME_LOAD_LENGTH;
            break;
    }

    return oneLineLength / vcTypeFullLength;
}

/**
 * @brief 通过要填充的数据长度(LOAD数) 得到填充完毕后的总的Frame数量, (一行的数量 * splitedCols)
 * @param bufferLength
 * @param vcType
 * @param splitedCols
 * @return
 */
size_t getFrameNumFromBufferLength(size_t bufferLength, enum VC_TYPE vcType, uint16_t splitedCols) {
    return getFrameNumOneLineFromBufferLength(bufferLength, vcType, splitedCols) * splitedCols;
}

/**
 * @brief 通过要填充的数据长度(LOAD数) 得到填充完毕后的总的数据长度数 (FULL LENGTH)
 * @param bufferLength 要填充的数据长度
 * @param vcType VC数据类型
 * @param splitedCols SQ值
 * @return 填充完毕后的总的数据长度数
 */
size_t getTotalFullLengthFormBufferLength(size_t bufferLength, enum VC_TYPE vcType, uint16_t splitedCols) {
    size_t headerLength;
    switch (vcType) {
        case VC_4:
            headerLength = VC4_FRAME_FULL_LENGTH;
            break;
        case VC_12:
            headerLength = VC12_FRAME_FULL_LENGTH;
            break;
    }

    size_t frameNum = getFrameNumFromBufferLength(bufferLength, vcType, splitedCols);
    return frameNum * headerLength;
}

size_t getTotalLengthOneLineFromBufferLength(size_t bufferLength, enum VC_TYPE vcType, uint16_t splitedCols) {
    if (bufferLength == 0) {
        return 0;
    }

    size_t vcTypeFullLength;

    switch (vcType) {
        case VC_4:
            vcTypeFullLength = VC4_FRAME_FULL_LENGTH;
            break;
        case VC_12:
            vcTypeFullLength = VC12_FRAME_FULL_LENGTH;
            break;
        default:
            vcTypeFullLength = VC4_FRAME_FULL_LENGTH;
            break;
    }

    return getFrameNumOneLineFromBufferLength(bufferLength, vcType, splitedCols) * vcTypeFullLength;

}


size_t generateGeneralData(enum GENERATE_DATA_TYPE type, char *data, size_t length) {
}

/**
 * @brief 通过memset全零填充
 *
 * @param buffer 已经分配的空间指针
 * @param filledLength 已经分配的空间大小
 * @return 填充的字节数
 */
size_t fillBlockWithZero(void *buffer, size_t filledLength) {
    // 开始全零填充
#ifdef DEBUG
    printf("全零填充前:\n");
    for (size_t i = 0; i < filledLength; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");
#endif // DEBUG

    memset(buffer, 0x00, filledLength);

#ifdef DEBUG
    printf("全零填充后:\n");
    for (size_t i = 0; i < filledLength; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");
#endif // DEBUG

    // 返回填充后的长度
    return filledLength;
}

/**
 * @brief 通过memset填充指定的单字节数据
 * @param buffer 已经分配的空间指针
 * @param filledLength 已经分配的空间大小
 * @param value 将填充的单字节指
 * @return 填充的字节数
 */
size_t fillBlockWithSpecificValue(void *buffer, size_t filledLength, uint8_t value) {
    // 开始全零填充
#ifdef DEBUG
    printf("全零填充前:\n");
    for (size_t i = 0; i < filledLength; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");
#endif // DEBUG

    memset(buffer, value, filledLength);

#ifdef DEBUG
    printf("全零填充后:\n");
    for (size_t i = 0; i < filledLength; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");
#endif // DEBUG

    // 返回填充后的长度
    return filledLength;
}

/**
 * @brief 产生固定数据, 数据写死为0x60A1DA8E, 函数首先会将这个数据块全零填充, 后续将按照 0-filledLength 的范围填充数据, 剩余的空间填充0
 * TODO: 这个函数有改进空间.
 *
 * @param buffer 已经分配的空间指针
 * @param bufferLength 已经分配的空间长度
 * @param filledLength 将要填充的数据字节数
 * @return 填充的字节数
 */
size_t generatePersistData(char *buffer, size_t bufferLength, size_t filledLength) {
    if (buffer == NULL || filledLength == 0) {
        return 0; // 无效的输入参数，不进行填充
    }
    // 全零填充
    fillBlockWithZero(buffer, bufferLength);

    // 开始填充数据
    // 使用PDF中说要填充的固定数据为: 0x60A1DA8E, 这很明显是一个4Bytes的数据, 有可能需要检验buffer的大小是不是4Bytes的整数倍.
    const size_t patternLength = 4; // 0x60A1DA8E 是4个字节
    const char pattern[] = {0x60, 0xA1, 0xDA, 0x8E};
    size_t filledBytes = 0;

    for (size_t i = 0; i < filledLength; i++) {
        buffer[i] = pattern[i % patternLength];
        filledBytes++;

        if (filledBytes >= filledLength) {
            break; // 已经填充满 buffer
        }
    }

    // 继续填充为零
    for (size_t i = filledBytes; i < filledLength; i++) {
        buffer[i] = 0x00;
    }
#ifdef DEBUG
    printf("填充后:\n");
    for (size_t i = 0; i < filledLength; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");

#endif // DEBUG
    // 填充数据结束

    return filledBytes;
}

/**
 * @brief 将传入的数据翻转, 直接更改传入的数据块
 *
 * @param buffer 传入数据块指针
 * @param length 数据块长度
 * @return 翻转是否成功. true为成功. false为失败.
 */
bool reverseBufferInPlace(char *buffer, size_t length) {
    if (buffer == NULL || length <= 1) {
        return false; // 无效的输入参数或数据长度太短，不进行翻转
    }

    // 使用两个指针，从头和尾同时向中间遍历，交换数据
    char temp;
    for (size_t i = 0, j = length - 1; i < j; i++, j--) {
        temp = buffer[i];
        buffer[i] = buffer[j];
        buffer[j] = temp;
    }
#ifdef DEBUG
    printf("翻转后:\n");
    for (size_t i = 0; i < length; i++)
    {
        printf("%02X ", (unsigned char)buffer[i]);
    }
    printf("\n");

#endif // DEBUG
    return true;
}

/**
 * @brief 将传入的数据翻转, 输出到额外的空间中, 传入的数据块保持不变.
 *
 * @param originBuffer 传入数据的指针
 * @param length 传入数据长度
 * @param outBuffer 输出数据指针
 */
void reverseBufferWithExtraBuffer(const char *originBuffer, size_t length, char *outBuffer) {
    if (originBuffer == NULL || outBuffer == NULL || length == 0) {
        return; // 无效的输入参数，不进行翻转
    }

    // 使用两个指针，从头和尾同时向中间遍历，翻转数据并保存到 outBuffer
    for (size_t i = 0; i < length; i++) {
        outBuffer[i] = originBuffer[length - 1 - i];
    }
#ifdef DEBUG
    printf("翻转后:\n");
    for (size_t i = 0; i < length; i++)
    {
        printf("%02X ", (unsigned char)outBuffer[i]);
    }
    printf("\n");

#endif // DEBUG
}

/**
 * @brief 重要函数, 用于将产生的块数据按照字节间插的方式填充进指定的数组. 注意: 这个函数不会产生对应的数据头, 数据头将会被保留, 并填充0.
 * @details 输入一个数据块和它的大小, 指定数据类型和SQ值, 输入一个能容纳输出的二维数组outBuffer[splitedCols][outBufferOneLineLength]和这个二维数组的行数(splitedCols)和列数(outBufferOneLineLength).
 *          buffer将会将按照字节间插的方式输出到outBuffer中.  下面是一个示例.
 *          注意: 下面的使用字符填充作为举例, 实际填充按照字节为单位进行. (其实差不多)
 *
 * @example
 * buffer="Hello, World!", VC_TYPE=VC_4, splitedCols=2.
 * outBuffer[0][VC_4_LENGTH] = { '0','0','0','0'......., 'H', 'l', 'o', 'W', 'r', 'd', '\0', '※', '※', '※', ..... ,'※' }
 * outBuffer[1][VC_4_LENGTH] = { '0','0','0','0'......., 'e', 'l', ' ', 'o', 'l', '!', '※', '※', '※', '※', ......,'※' }
 *                              前面的开销部分将会保留       这里是实际填充的数据            如果outBuffer的一列Frame能够承载,后面维持不变(不填充0);
 *
 *
 * @example 正常情况下应该是这样的
 * buffer="Hello, World!..........(非常长)", VC_TYPE=VC_4, splitedCols=2.
 * outBuffer[0][VC_4_LENGTH] = { '0','0',......,'H','l','o','W','r','d','H','l','o', ......,'d','H','0','0','0',......,'l','o','W','r','d','H','l','o',.............., '※', '※', '※', ..... ,'※' }
 * outBuffer[1][VC_4_LENGTH] = { '0','0',......,'e','l',' ','o','l','!','e','l',' ', ......,'!','e','0','0','0',......,'l',' ','o','l','!','e','l',' ',.............., '※', '※', '※', ..... ,'※'}
 *                                                                                                 |
 *                                                                                                 |
 *                                       (Frame1)                                      这个位置为一个VC_4 Frame的长度            (Frame2)   (Frame3).....          最后,buffer的数据填充完了,Frame还有空余,维持不变
 *
 * @param buffer 输入的块数据指针
 * @param bufferLength 输入的块数据大小
 * @param vcType 将要转换成的数据类型,这将指定输出单个Frame大小
 * @param splitedCols SQ值,将指定字节间插的行数.
 * @param outBufferOneLineLength 输出数据块单行大小. 可以通过 getTotalFullLengthFormBufferLength() 函数获取.
 * @param outBuffer 是outBuffer[splitedCols][outBufferOneLineLength]的指针.
 * @return 处理的字节个数.
 */
size_t splitIntoMutipleBuffer(const char *buffer, size_t bufferLength, enum VC_TYPE vcType, uint16_t splitedCols,
                              size_t outBufferOneLineLength, char outBuffer[splitedCols][outBufferOneLineLength]) {
    if (buffer == NULL || bufferLength == 0 || splitedCols <= 0 || outBuffer == NULL) {
        return 0; // 输入参数不合法
    }

    size_t fullSize;
    size_t bodySize;
    size_t loadSize;
    size_t headerSize = VC_FRAME_HEADER_LENGTH;
    switch (vcType) {
        case VC_4:
            fullSize = VC4_FRAME_FULL_LENGTH;
            bodySize = VC4_FRAME_BODY_LENGTH;
            loadSize = VC4_FRAME_LOAD_LENGTH;

            break;
        case VC_12:
            fullSize = VC12_FRAME_FULL_LENGTH;
            bodySize = VC12_FRAME_BODY_LENGTH;
            loadSize = VC12_FRAME_LOAD_LENGTH;
            break;
        default:
            fullSize = VC4_FRAME_FULL_LENGTH;
            bodySize = VC4_FRAME_BODY_LENGTH;
            loadSize = VC4_FRAME_LOAD_LENGTH;
            break;
    }

    size_t oneLineFrameNum = getFrameNumOneLineFromBufferLength(bufferLength, vcType, splitedCols);

//    // 这个部分填充是header部分
//    // TODO: 目前填充的还是0
//    for (size_t lineFrameNum = 0; lineFrameNum < oneLineFrameNum; lineFrameNum++) {
//        for (size_t sq = 0; sq < splitedCols; sq++) {
//            for (size_t bytes = 0; bytes < VC_FRAME_HEADER_LENGTH; bytes++) {
//                outBuffer[sq][bytes + lineFrameNum * fullSize] = 0x00;
//            }
//        }
//    }

#ifdef DEBUG
    printf("fill header with 0 complete!\n");
    for (size_t i = 0; i < splitedCols; i++) {
        printf("outerBuffer[%d]:\n", i);
        for (size_t j = 0; j < outBufferOneLineLength; j++) {
            if (j % fullSize == 0) {
                printf("\n");
            }
            printf("%02X ", (unsigned char) outBuffer[i][j]);

        }
        printf("\n");
    }
#endif

    // 这个部分填充的是LOAD.
    size_t originBufferSeek = 0;
    for (size_t lineFrameNum = 0; lineFrameNum < oneLineFrameNum; lineFrameNum++) {     // lineFrameNum作为定位计数使用.
        for (size_t bytes = headerSize; bytes < fullSize; bytes++) {     // 针对每个字节
            for (size_t sq = 0; sq < splitedCols; sq++) {                                        // 遍历SQ放入.
                if (originBufferSeek < bufferLength) {
                    outBuffer[sq][bytes + fullSize * lineFrameNum] = buffer[originBufferSeek];
                    originBufferSeek++;
                } else {
                    break;      // 如果填充完毕, 后面的原始数据不动
                }
            }
        }
    }
#ifdef DEBUG
    printf("fill LOAD complete!\n");
    for (size_t i = 0; i < splitedCols; i++) {
        printf("outerBuffer[%zu]:\n", i);
        for (size_t j = 0; j < outBufferOneLineLength; j++) {
            if (j % fullSize == 0) {
                printf("\n");
            }
            printf("%02X ", (unsigned char) outBuffer[i][j]);
        }
        printf("\n");
    }

    printf("originBufferSeek %zu\n", originBufferSeek);
#endif
    return originBufferSeek;
}

vcTypeHeader_t
generateHeaderWithSpecificValue(enum VC_TYPE vcType, uint16_t logicalChannelID, uint16_t physicalChannelID, uint16_t SQ,
                                size_t frameLength, uint16_t frameNum, uint16_t MFI) {
    vcTypeHeader_t pattern;

    pattern.logicalChannelID = logicalChannelID;
    pattern.physicalChannelID = physicalChannelID;
    pattern.SQ = SQ;
    pattern.vcType = vcType;
    pattern.frameLength = frameLength;
    pattern.frameNum = frameNum;
    pattern.MFI = MFI;

    return pattern;

}

void
fillHeaderWithSpecificValue(vcTypeHeader_t *target, enum VC_TYPE vcType, uint16_t logicalChannelID,
                            uint16_t physicalChannelID, uint16_t SQ,
                            size_t frameLength, uint16_t frameNum, uint16_t MFI) {
    target->logicalChannelID = logicalChannelID;
    target->physicalChannelID = physicalChannelID;
    target->SQ = SQ;
    target->vcType = vcType;
    target->frameLength = frameLength;
    target->frameNum = frameNum;
    target->MFI = MFI;
}

/**
 * 传入相关的信息, 按照传入行数和列数将那个frame位置的头部(HEADER)填充.
 * @param vcType
 * @param splitedCols
 * @param inputBufferOneLineLength
 * @param inputBuffer
 * @param headerData
 * @param targetRowFrameIndex
 * @param targetColFrameIndex
 * @return 成功true  失败false
 */
bool fillHeaderToSplitFrameBuffersWithRowCol(enum VC_TYPE vcType, int16_t splitedCols, size_t inputBufferOneLineLength,
                                             char inputBuffer[splitedCols][inputBufferOneLineLength],
                                             vcTypeHeader_t headerData,
                                             size_t targetRowFrameIndex, size_t targetColFrameIndex) {
    if (inputBuffer == NULL || inputBufferOneLineLength == 0) {
        return false;
    }

    if (targetColFrameIndex > splitedCols - 1 ||
        targetRowFrameIndex > getFrameNumOneLineFromOneLineLength(vcType, inputBufferOneLineLength) - 1) {
        // 超过要填充的范围.
        return false;
    }

    size_t fullSize;
    size_t bodySize;
    size_t loadSize;

    switch (vcType) {
        case VC_4:
            fullSize = VC4_FRAME_FULL_LENGTH;
            bodySize = VC4_FRAME_BODY_LENGTH;
            loadSize = VC4_FRAME_LOAD_LENGTH;

            break;
        case VC_12:
            fullSize = VC12_FRAME_FULL_LENGTH;
            bodySize = VC12_FRAME_BODY_LENGTH;
            loadSize = VC12_FRAME_LOAD_LENGTH;
            break;
        default:
            fullSize = VC4_FRAME_FULL_LENGTH;
            bodySize = VC4_FRAME_BODY_LENGTH;
            loadSize = VC4_FRAME_LOAD_LENGTH;
            break;
    }

//    printf("当前传入的Header: \n");
//    printVCTypeHeader(&headerData);

    // 这个部分填充是header部分
    // Row是行, Col是列
    char headerDataArr[sizeof(vcTypeHeader_t)];
    memcpy_s(headerDataArr, sizeof(vcTypeHeader_t), &headerData, sizeof(vcTypeHeader_t));

//    printf("处理成为array的Header:\n");
//    vcTypeHeader_t* headerArrPtr = (vcTypeHeader_t*)headerDataArr;
//    printVCTypeHeader(headerArrPtr);

    // print test.

//#ifdef DEBUG
    for (int i = 0; i < sizeof(vcTypeHeader_t); ++i) {
        printf("%02X ", (unsigned char) headerDataArr[i]);
    }
    printf("\n");
//#endif

    for (size_t currByte = 0; currByte < VC_FRAME_HEADER_LENGTH; ++currByte) {
        inputBuffer[targetColFrameIndex][(targetRowFrameIndex * fullSize) + currByte] = (char) headerDataArr[currByte];
    }
    return true;
}

void
fillHeadersToSplitBuffer(vcTypeHeader_t startHeader, enum VC_TYPE vcType, uint16_t splitedCols,
                         size_t inputBufferOneLineLength,
                         char inputBuffer[splitedCols][inputBufferOneLineLength]) {
    vcTypeHeader_t patternHeader = startHeader;

    // 填充部分
    size_t totalRowNum = getFrameNumOneLineFromOneLineLength(vcType, inputBufferOneLineLength);
    size_t totalColNum = splitedCols;

    size_t currFrameNum = 0;
    for (size_t currRow = 0; currRow < totalRowNum; ++currRow) {
        for (size_t currCol = 0; currCol < totalColNum; ++currCol) {
            // 处理header部分.
            patternHeader.SQ = currCol % totalColNum;
            patternHeader.vcType = vcType;
            patternHeader.frameNum = currFrameNum;
            patternHeader.MFI = currRow % 4096;     // 最大的MFI为4095, 取模4096.



            fillHeaderToSplitFrameBuffersWithRowCol(vcType, splitedCols, inputBufferOneLineLength, inputBuffer,
                                                    patternHeader, currRow, currCol);
            currFrameNum++;
        }
    }
}

bool outputToFiles(uint16_t splitedCols, size_t inputBufferOneLineLength,
                   char inputBuffer[splitedCols][inputBufferOneLineLength]) {

    // 假设有5个文件分别为 file1.txt, file2.txt, file3.txt, file4.txt, file5.txt
    // 将这5个文件依次打开，并将每个文件的内容分别存入 inputBuffer 中对应行的所有字节
    for (size_t currCol = 0; currCol < splitedCols; currCol++) {
        char filename[20];
        sprintf(filename, "Data_%zu.dat", currCol); // 生成文件名，例如：file1.txt, file2.txt, ...

        FILE *file = fopen(filename, "ab"); // 以只读模式打开文件
        if (file == NULL) {
            printf("Cannot open files: %s\n", filename);
            return false;
        }

        // 将 inputBuffer 的第 currCol 行读取到文件内容中
        size_t bytesFilled = fwrite(inputBuffer[currCol], sizeof(char), inputBufferOneLineLength, file);

        fclose(file);
    }

    // 现在 inputBuffer 中存放了所有文件的内容，您可以在这里对 inputBuffer 进行进一步处理

    // 示例：打印每行的内容
//    for (int i = 0; i < splitedCols; i++) {
//        printf("第 %d 行内容：%s\n", i + 1, inputBuffer[i]);
//    }

    return true;
}

void testAllFunctions() {
    uint16_t defaultSplitedCols = 3;
    enum VC_TYPE defaultVCType = VC_4;

    //////////////////  generatePersistData()
    const size_t fillBufferLength = 5000; // 要填充的 buffer 的长度
    const size_t bufferLength = 5000;     // 总 buffer 长度
    char buffer[bufferLength];

    size_t filledBytes = generatePersistData(buffer, bufferLength, fillBufferLength);

    /*
    printf("buffer data bytes: %zu\n", filledBytes);
    printf("filled buffer data: \n");
    for (size_t i = 0; i < bufferLength; i++) {
        printf("%02X ", (unsigned char) buffer[i]);
    }
    printf("\n");

    /////////////////////////   reverseInPlace()
    reverseBufferInPlace(buffer, bufferLength);

//    printf("reverse buffer: \n");
//    for (size_t i = 0; i < bufferLength; i++) {
//        printf("%02X ", (unsigned char) buffer[i]);
//    }
//    printf("\n");

    /////////////////////////   reverseWithExtraBuffer()
    char buffer2[bufferLength];
    reverseBufferWithExtraBuffer(buffer, bufferLength, buffer2);

//    printf("reverse buffer2: \n");
//    for (size_t i = 0; i < bufferLength; i++) {
//        printf("%02X ", (unsigned char) buffer2[i]);
//    }
//    printf("\n");

     */

    ///////////////////////// getFrameNumFromBufferLength(), getFrameNumOneLineFromBufferLength()
    size_t buffersNum1 = getFrameNumOneLineFromBufferLength(bufferLength, defaultVCType, defaultSplitedCols);
    printf("getFrameNumOneLineFromBufferLength() returns: %zu\n", buffersNum1);
    size_t buffersNum2 = getFrameNumFromBufferLength(bufferLength, defaultVCType, defaultSplitedCols);
    printf("getFrameNumFromBufferLength() returns: %zu\n", buffersNum2);

    // 变回原来的
//    reverseBufferInPlace(buffer, bufferLength);
//    printf("reverse to origin buffer\n");

    printf("//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n");

    size_t totalFramesLength = getTotalFullLengthFormBufferLength(bufferLength, defaultVCType, defaultSplitedCols);
    printf("totalFramesLength: %zu\n", totalFramesLength);

    size_t oneLineFrameNum = getFrameNumOneLineFromBufferLength(bufferLength, defaultVCType, defaultSplitedCols);
    size_t oneLineLength = getTotalLengthOneLineFromBufferLength(bufferLength, defaultVCType, defaultSplitedCols);

    char outerBuffer[defaultSplitedCols][oneLineLength];
    // 全部填充BB.
    fillBlockWithSpecificValue(outerBuffer, totalFramesLength, 0xBB);

//    printf("filled outBuffer data: \n");
//    for (size_t i = 0; i < SQ; i++) {
//        printf("outerBuffer[%d]:\n", i);
//        for (size_t j = 0; j < outBufferOneLineLength; j++) {
//            if (j % headerSize == 0) {
//                printf("\n");
//            }
//            printf("%02X ", (unsigned char) outBuffer[i][j]);
//        }
//        printf("\n");
//    }

    splitIntoMutipleBuffer(buffer, bufferLength, defaultVCType, defaultSplitedCols, oneLineLength, outerBuffer);
    printf("splitIntoMutipleBuffer complete!\n");
//    for (size_t i = 0; i < defaultSplitedCols; i++) {
//        printf("outerBuffer[%zu]:\n", i);
//        for (size_t j = 0; j < oneLineLength; j++) {
//            if (j % VC4_FRAME_FULL_LENGTH == 0) {
//                printf("\n");
//            }
//            printf("%02X ", (unsigned char) outerBuffer[i][j]);
//        }
//        printf("\n");
//    }

    printf("vcTypeHeaderLength = %zd\n", VC_FRAME_HEADER_LENGTH);
    printf("//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n");
    vcTypeHeader_t defaultHeader = {1, 1, 1, 1, 1, 1, 1};

//    size_t defaultRow, defaultCol;
//
//    defaultRow = 0, defaultCol = 0;
//    if (fillHeaderToSplitFrameBuffersWithColIndex(VC_4, defaultSplitedCols, oneLineLength, outerBuffer, defaultHeader,
//                                                defaultRow,
//                                                defaultCol)) {
//        printf("fillHeaderToSplitBuffers() success \n");
//    } else printf("fillHeaderToSplitBuffers() failed \n");
//
//    defaultRow = 3, defaultCol = 2;
//    if (fillHeaderToSplitFrameBuffersWithColIndex(VC_4, defaultSplitedCols, oneLineLength, outerBuffer, defaultHeader,
//                                                defaultRow,
//                                                defaultCol)) {
//        printf("fillHeaderToSplitBuffers() success \n");
//    } else printf("fillHeaderToSplitBuffers() failed \n");
//

    size_t FRAME_FULL_LENGTH;
    switch (defaultVCType) {
        case VC_4:
            FRAME_FULL_LENGTH = VC4_FRAME_FULL_LENGTH;
            break;
        case VC_12:
            FRAME_FULL_LENGTH = VC12_FRAME_FULL_LENGTH;
            break;
    }


    for (size_t i = 0; i < defaultSplitedCols; i++) {
        printf("outerBuffer[%zu]:\n", i);
        for (size_t j = 0; j < oneLineLength; j++) {
            if (j % FRAME_FULL_LENGTH == 0) {
                printf("\n");
            }
            printf("%02X ", (unsigned char) outerBuffer[i][j]);
        }
        printf("\n");
    }

    printf("////////////////////////////////////////////////////////////////////\n");

    vcTypeHeader_t header1 = generateHeaderWithSpecificValue(defaultVCType, 23, 50, 0, bufferLength, 0, 0);
    fillHeadersToSplitBuffer(header1, defaultVCType, defaultSplitedCols, oneLineLength, outerBuffer);

    printf("fillHeadersToSplitBuffer start!\n");
    for (size_t i = 0; i < defaultSplitedCols; i++) {
        printf("outerBuffer[%zu]:\n", i);
        for (size_t j = 0; j < oneLineLength; j++) {
            if (j % FRAME_FULL_LENGTH == 0) {
                printf("\n");
            }
            printf("%02X ", (unsigned char) outerBuffer[i][j]);
        }
        printf("\n");
    }

    outputToFiles(defaultSplitedCols, oneLineLength, outerBuffer);


}

int main() {
    testAllFunctions();

    return 0;
}
